﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace Lcsoft.TemplateEngine.Core
{
	/// <summary>
	/// 提供一组方法和属性，实现多语言引擎的功能。
	/// </summary>
	[ComVisible(true)]
	[Serializable]
	public abstract class MultiLanguageEngineBase
	{
		private readonly string _languagePath = String.Empty;

		/// <summary>
		/// 初始化多语言引擎。
		/// </summary>
		/// <param name="languagePath">指定语言包所在的完整路径。</param>
		/// <param name="languageCode">指定当前正在使用的语言代码。</param>
		protected MultiLanguageEngineBase(string languagePath, string languageCode)
		{
			if (languagePath == null) throw new ArgumentNullException("languagePath");
			if (languagePath.Length == 0) throw new ArgumentOutOfRangeException("languagePath");
			if (Path.IsPathRooted(languagePath) == false) throw new ArgumentException("参数 languagePath 必须是绝对路径。", "languagePath");
			if (Directory.Exists(languagePath) == false) throw new DirectoryNotFoundException(String.Format(@"无法找到指定路径：""{0}""。", languagePath));

			if (languageCode == null) throw new ArgumentNullException("languageCode");
			if (languageCode.Length == 0) throw new ArgumentOutOfRangeException("languageCode");

			this._languagePath = languagePath;
			this.LanguageCode = languageCode;

			this._Initialize();
		}

		/// <summary>
		/// 获取指定名称的语言项的内容。
		/// </summary>
		/// <param name="langName">指定语言项的名称。</param>
		/// <returns>如果找到指定的语言项则返回指定语言项的内容，否则将返回 <see cref="String.Empty"/>。</returns>
		public string this[string langName]
		{
			get { return this.ReadValue(langName); }
		}

		/// <summary>
		/// 获取当前正在使用的语言包。
		/// </summary>
		public LanguagePack LanguagePack
		{
			get { return this.LanguagePacks == null || !this.LanguagePacks.Any() ? LanguagePack.Empty : (this.LanguagePacks.ContainsKey(this.LanguageCode) ? this.LanguagePacks[this.LanguageCode] : LanguagePack.Empty); }
		}

		/// <summary>
		/// 获取所有可用的语言包的集合。
		/// </summary>
		public SafeDictionary<string, LanguagePack> LanguagePacks { get; private set; }

		/// <summary>
		/// 获取或设置当前正在使用的语言代码。
		/// </summary>
		public string LanguageCode { get; set; }

		private void _Initialize()
		{
			this.LanguagePacks = new SafeDictionary<string, LanguagePack>(StringComparer.InvariantCultureIgnoreCase);
			this.Initialize();
		}

		/// <summary>
		/// 继承此类时实现多语言引擎的初始化，初始化时从指定路径载入语言项的集合。
		/// </summary>
		/// <remarks>在这里您可以自定义自己的语言包格式和实现的细节。</remarks>
		protected virtual void Initialize()
		{
			if (Directory.Exists(this._languagePath) == false) throw new ParseException("IO 错误", String.Format("未能找到指定语言包目录（{0}）。", this._languagePath));

			var dirs = Directory.GetDirectories(this._languagePath, "*", SearchOption.TopDirectoryOnly);

			foreach (var dir in dirs)
			{
				var code = dir.Substring(dir.LastIndexOf('\\') + 1);
				var pack = new LanguagePack(code);

				var files = Directory.GetFiles(dir, "*.mui", SearchOption.AllDirectories);

				foreach (var file in files)
				{
					var lines = File.ReadAllLines(file);

					if (lines.Length == 0) continue;

					foreach (var line in lines)
					{
						if (String.IsNullOrWhiteSpace(line)) continue;

						var m = line.IndexOf('=');

						var name = line.Substring(0, m).Trim();
						var value = line.Substring(m + 1).Trim();

						if (String.IsNullOrEmpty(name)) continue;

						pack.Items.Add(new LanguageItem(name, value, pack));
					}
				}

				this.LanguagePacks.Add(code, pack);
			}
		}

		/// <summary>
		/// 读取指定名称的语言项的内容。
		/// </summary>
		/// <param name="langName">指定语言项的名称。</param>
		/// <returns>如果找到指定的语言项则返回指定语言项的内容，否则将返回 <see cref="String.Empty"/>。</returns>
		public string ReadValue(string langName) { return this.ReadValue(langName, this.LanguageCode); }

		/// <summary>
		/// 读取指定语言代码类型的且具有指定名称的语言项的内容。
		/// </summary>
		/// <param name="langName">指定语言项的名称。</param>
		/// <param name="langCode">指定语言类型的代码。</param>
		/// <returns>如果找到指定的语言项则返回指定语言项的内容，否则将返回 <see cref="String.Empty"/>。</returns>
		public string ReadValue(string langName, string langCode)
		{
			if (this.LanguagePacks == null || !this.LanguagePacks.Any()) return String.Empty;
			if (this.LanguagePacks.ContainsKey(langCode) == false) return String.Empty;

			var lang = this.LanguagePacks[langCode][langName].Value;

			return string.IsNullOrEmpty(lang) ? String.Empty : lang;
		}
	}
}
